﻿
Imports std
Imports lock_t = lock(Of locks.simplelock)
Imports deliverers_t = std.hashmap(Of System.UInt32, std.vector(Of osi.output.deliverer_t), _31, _uint32_to_uint32)

Public Class output
    Private Shared ReadOnly deliverers As deliverers_t = Nothing
    Private Shared fixed As Boolean = False
    Private Shared deliverers_lock As lock_t

    Shared Sub New()
        deliverers = New deliverers_t()
    End Sub

    Public Shared Sub fix()
        fixed = True
    End Sub

    Public Shared Function register(ByVal mode As UInt32, ByVal d As deliverer_t) As Boolean
        If fixed OrElse d Is Nothing Then
            Return False
        Else
            Dim rtn As Boolean = False
            deliverers_lock.wait()
            rtn = deliverers(mode).push_back(d)
            deliverers_lock.release()
            Return rtn
        End If
    End Function

    Public Shared Function deliver(ByVal mode As UInt32, ByVal cs() As [case]) As eventComb
        Dim i As Int64 = 0
        Dim ec As eventComb = Nothing
        Return New eventComb(Function() As Boolean
                                 If cs Is Nothing OrElse cs.Length() = 0 Then
                                     Return goto_end()
                                 Else
                                     Return goto_next()
                                 End If
                             End Function,
                             Function() As Boolean
                                 assert(i < cs.Length())
                                 ec = deliver(mode, cs(i))
                                 Return waitfor(ec) AndAlso
                                        goto_next()
                             End Function,
                             Function() As Boolean
                                 If ec.end_result() Then
                                     i += 1
                                     If i < cs.Length() Then
                                         Return goto_prev()
                                     Else
                                         Return goto_end()
                                     End If
                                 Else
                                     Return False
                                 End If
                             End Function)
    End Function

    Public Shared Function deliver(ByVal mode As UInt32, ByVal c As [case]) As eventComb
        Dim ecs As vector(Of eventComb) = Nothing
        Return New eventComb(Function() As Boolean
                                 Dim rtn As Boolean = False
                                 If Not fixed Then
                                     deliverers_lock.wait()
                                 End If

                                 Dim it As deliverers_t.iterator = Nothing
                                 it = deliverers.find(mode)
                                 If it = deliverers.end() Then
                                     rtn = False
                                 Else
                                     assert(Not (+it).second Is Nothing)
                                     assert((+it).second.size() > 0)
                                     ecs = New vector(Of eventComb)()
                                     For i As Int64 = 0 To (+it).second.size() - 1
                                         ecs.push_back((+it).second(i).deliver(c))
                                     Next
                                     rtn = True
                                 End If

                                 If Not fixed Then
                                     deliverers_lock.release()
                                 End If
                                 Return rtn AndAlso
                                        waitfor(+ecs) AndAlso
                                        goto_next()
                             End Function,
                             Function() As Boolean
                                 assert(Not ecs Is Nothing)
                                 assert(ecs.size() > 0)
                                 For i As Int64 = 0 To ecs.size() - 1
                                     If Not ecs(i).end_result() Then
                                         Return False
                                     End If
                                 Next
                                 Return goto_end()
                             End Function)
    End Function
End Class
